#![allow(dead_code)]
use std::collections::HashMap;

mod pid;
mod print;
use pid::*;

#[derive(Debug)]
pub struct ProcTreeNode {
    subs: Vec<ProcTreeNode>,
    name: String,
    pid: i32,
}

fn build_node(
    pid: i32,
    name: String,
    proc_infos: &Vec<ProcInfo>,
    node_tree: &HashMap<i32, Vec<usize>>,
) -> ProcTreeNode {
    let mut node = ProcTreeNode {
        subs: vec![],
        name,
        pid,
    };

    if let Some(subs) = node_tree.get(&pid) {
        for s in subs {
            let info = &proc_infos[*s];
            node.subs.push(build_node(
                info.pid,
                info.name.clone(),
                proc_infos,
                node_tree,
            ));
        }
    }

    node
}

fn build_proc_tree(proc_infos: Vec<ProcInfo>) -> ProcTreeNode {
    let mut map = HashMap::new();

    for (i, p) in proc_infos.iter().enumerate() {
        if !map.contains_key(&p.ppid) {
            map.insert(p.ppid, vec![i]);
        } else {
            map.get_mut(&p.ppid).unwrap().push(i);
        }
    }

    build_node(
        1,
        proc_infos.iter().find(|x| x.pid == 1).unwrap().name.clone(),
        &proc_infos,
        &map,
    )
}

fn main() {
    let mut arg = std::env::args();

    let mut show_pid = false;
    let mut sort = false;
    if arg.len() == 2 {
        let arg = arg.nth(1).unwrap();
        if arg.contains('V') {
            eprintln!("balabala version 0.1");
            return;
        }
        if arg.contains('n') {
            sort = true;
        }
        if arg.contains('p') {
            show_pid = true;
        }
    }

    let pinfo: Vec<ProcInfo> = get_pids()
        .unwrap()
        .into_iter()
        .map(get_process_info_with_pid)
        .flatten()
        .collect();

    print::print_proc_tree(&build_proc_tree(pinfo), &print::PrintOpt { show_pid, sort });
}
